package es

import (
	"context"
	"fmt"
	"github.com/olivere/elastic/v7"
	"log"
	"niu-video/app/consts"
	"niu-video/config"
	"niu-video/pkg/logger"
	"os"
	"sync"
	"time"
)

type ElasticClient struct {
	Client  *elastic.Client
	Context context.Context
}

// once 确保全局的 es 对象只实例一次
var once sync.Once

var ES *ElasticClient

func InitElasticSearch() {
	url := fmt.Sprintf("http://%s:%d", config.Conf.Es.Host, config.Conf.Es.Port)
	once.Do(func() {
		client, err := elastic.NewClient(
			// elasticsearch 服务地址，多个服务地址使用逗号分隔
			elastic.SetURL(url),
			// 基于http base auth验证机制的账号和密码
			elastic.SetBasicAuth(config.Conf.Es.Username, config.Conf.Es.Password),
			// 启用gzip压缩
			elastic.SetGzip(true),
			// 设置监控检查时间间隔
			elastic.SetHealthcheckInterval(10*time.Second),
			// 设置请求失败最大重试次数
			elastic.SetMaxRetries(5),
			elastic.SetSniff(false),
			// 设置错误日志输出
			elastic.SetErrorLog(log.New(os.Stderr, "ELASTIC ", log.LstdFlags)),
			// 设置info日志输出
			elastic.SetInfoLog(log.New(os.Stdout, "", log.LstdFlags)),
			// 将sniff设置为false后，便不会自动转换地址
			elastic.SetSniff(false),
		)
		if err != nil {
			panic(err)
		}
		ES = &ElasticClient{
			Client:  client,
			Context: context.Background(),
		}
		err = ES.Ping(url)
		logger.LogIf(err)

		err = ES.CreateIndex(consts.VIDOE_ES_INDEX)
		logger.LogIf(err)
	})
}

// Ping 用以测试 es 连接是否正常
func (es *ElasticClient) Ping(url string) error {
	_, _, err := ES.Client.Ping(url).Do(context.Background())
	return err
}

func (ec *ElasticClient) CreateIndex(indexName string) error {
	_, err := ec.Client.CreateIndex(indexName).Do(context.Background())
	return err
}

func (ec *ElasticClient) IndexDocument(indexName string, document interface{}) error {
	_, err := ec.Client.Index().
		Index(indexName).
		BodyJson(document).
		Do(context.Background())
	return err
}

func (ec *ElasticClient) SearchDocuments(indexName string, query elastic.Query, page int, pageSize int) (*elastic.SearchResult, error) {
	result, err := ec.Client.Search().
		Index(indexName).
		Query(query).
		From((page - 1) * pageSize).
		Size(pageSize).
		Do(context.Background())
	return result, err
}

func (ec *ElasticClient) DeleteDocument(indexName string, videoId int64) error {
	q := elastic.NewMatchQuery("videoId", videoId)
	_, err := ec.Client.DeleteByQuery().
		Index(indexName).
		Query(q).
		Do(context.Background())
	return err
}
